package com.suep.data_analysis.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.suep.data_analysis.dto.AgentDto;
import com.suep.data_analysis.dto.TeamRecommendationDto;
import com.suep.data_analysis.model.Agent;
import com.suep.data_analysis.repository.AgentRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class TeamRecommendationService {
    private final AgentRepository agentRepository;
    private final AgentService agentService;

    // 职业分类
    private static final Set<String> MAIN_PROFESSIONS = Set.of("强攻", "命破", "异常");
    private static final Set<String> SUB_PROFESSIONS = Set.of("异常", "击破", "防护");
    private static final Set<String> SUPPORT_PROFESSIONS = Set.of("支援", "击破");  // 支援位置可以放击破

    /**
     * 为指定代理人推荐配队
     */
    public List<TeamRecommendationDto> recommendTeam(String agentId) {
        // 获取所有代理人
        List<Agent> allAgents = agentRepository.selectAllAgent();
        if (allAgents == null || allAgents.size() < 3) {
            return Collections.emptyList();
        }
        // 获取输入角色
        Optional<Agent> inputOpt = allAgents.stream().filter(a -> a.getAgentId().equals(agentId)).findFirst();
        if (inputOpt.isEmpty()) {
            throw new RuntimeException("代理人不存在");
        }
        Agent inputAgent = inputOpt.get();

        List<TeamRecommendationDto> recommendations = new ArrayList<>();
        // 按职业动态定位角色位置
        if (MAIN_PROFESSIONS.contains(inputAgent.getProfession())) {
            // 输入角色做主C
            List<Agent> subCandidates = allAgents.stream()
                    .filter(a -> !a.getAgentId().equals(agentId) && SUB_PROFESSIONS.contains(a.getProfession()))
                    .collect(Collectors.toList());
            List<Agent> supportCandidates = allAgents.stream()
                    .filter(a -> !a.getAgentId().equals(agentId) && SUPPORT_PROFESSIONS.contains(a.getProfession()))
                    .collect(Collectors.toList());
            for (Agent subAgent : subCandidates) {
                // 主C不是异常，副C不能是异常
                if (!"异常".equals(inputAgent.getProfession()) && "异常".equals(subAgent.getProfession())) {
                    continue;
                }
                for (Agent supportAgent : supportCandidates) {
                    if (subAgent.getAgentId().equals(supportAgent.getAgentId())) continue;
                    if (!isValidProfessionCombination(inputAgent, subAgent, supportAgent)) continue;
                    List<Agent> team = Arrays.asList(inputAgent, subAgent, supportAgent);
                    TeamRecommendationDto dto = createTeamRecommendation(inputAgent, team);
                    if (dto.isValidTeam()) {
                        recommendations.add(dto);
                    }
                }
            }
        } else if (SUB_PROFESSIONS.contains(inputAgent.getProfession())) {
            // 输入角色做副C
            List<Agent> mainCandidates = allAgents.stream()
                    .filter(a -> !a.getAgentId().equals(agentId) && MAIN_PROFESSIONS.contains(a.getProfession()))
                    .collect(Collectors.toList());
            List<Agent> supportCandidates = allAgents.stream()
                    .filter(a -> !a.getAgentId().equals(agentId) && SUPPORT_PROFESSIONS.contains(a.getProfession()))
                    .collect(Collectors.toList());
            for (Agent mainAgent : mainCandidates) {
                // 主C不是异常，副C不能是异常
                if (!"异常".equals(mainAgent.getProfession()) && "异常".equals(inputAgent.getProfession())) {
                    continue;
                }
                for (Agent supportAgent : supportCandidates) {
                    if (mainAgent.getAgentId().equals(supportAgent.getAgentId())) continue;
                    if (!isValidProfessionCombination(mainAgent, inputAgent, supportAgent)) continue;
                    List<Agent> team = Arrays.asList(mainAgent, inputAgent, supportAgent);
                    TeamRecommendationDto dto = createTeamRecommendation(mainAgent, team);
                    if (dto.isValidTeam()) {
                        recommendations.add(dto);
                    }
                }
            }
        } else if (SUPPORT_PROFESSIONS.contains(inputAgent.getProfession())) {
            // 输入角色做支援
            List<Agent> mainCandidates = allAgents.stream()
                    .filter(a -> !a.getAgentId().equals(agentId) && MAIN_PROFESSIONS.contains(a.getProfession()))
                    .collect(Collectors.toList());
            List<Agent> subCandidates = allAgents.stream()
                    .filter(a -> !a.getAgentId().equals(agentId) && SUB_PROFESSIONS.contains(a.getProfession()))
                    .collect(Collectors.toList());
            for (Agent mainAgent : mainCandidates) {
                for (Agent subAgent : subCandidates) {
                    // 主C不是异常，副C不能是异常
                    if (!"异常".equals(mainAgent.getProfession()) && "异常".equals(subAgent.getProfession())) {
                        continue;
                    }
                    if (mainAgent.getAgentId().equals(subAgent.getAgentId())) continue;
                    if (!isValidProfessionCombination(mainAgent, subAgent, inputAgent)) continue;
                    List<Agent> team = Arrays.asList(mainAgent, subAgent, inputAgent);
                    TeamRecommendationDto dto = createTeamRecommendation(mainAgent, team);
                    if (dto.isValidTeam()) {
                        recommendations.add(dto);
                    }
                }
            }
        } else {
            // 其他职业暂不支持
            return Collections.emptyList();
        }
        // 去重并排序
        List<TeamRecommendationDto> uniqueList = recommendations.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toMap(
                                dto -> dto.getMainAgent().getAgentId() + "-" +
                                        dto.getTeamMembers().stream().map(AgentDto::getAgentId).sorted().collect(Collectors.joining("-")),
                                dto -> dto,
                                (a, b) -> a
                        ),
                        m -> new ArrayList<>(m.values())
                ));
        uniqueList.sort(Comparator.comparingInt(TeamRecommendationDto::getMatchScore).reversed());
        return uniqueList;
    }

    // 校验职业组合规则
    private boolean isValidProfessionCombination(Agent main, Agent sub, Agent support) {
        // 副C职业
        if (!SUB_PROFESSIONS.contains(sub.getProfession())) return false;
        // 支援职业
        if (!SUPPORT_PROFESSIONS.contains(support.getProfession())) return false;
        // 主C不是异常，副C不能是异常
        if (!"异常".equals(main.getProfession()) && "异常".equals(sub.getProfession())) return false;
        // 特殊配队规则
        if ("防护".equals(sub.getProfession()) && "击破".equals(support.getProfession())) return true;
        if ("击破".equals(support.getProfession()) && !"防护".equals(sub.getProfession())) return false;
        return true;
    }

    private TeamRecommendationDto createTeamRecommendation(Agent mainAgent, List<Agent> team) {
        TeamRecommendationDto dto = new TeamRecommendationDto();
        dto.setMainAgent(convertToDto(mainAgent));
        dto.setTeamMembers(team.stream()
                .filter(agent -> !agent.getAgentId().equals(mainAgent.getAgentId()))
                .map(this::convertToDto)
                .collect(Collectors.toList()));
        // 计算匹配分数
        int score = calculateMatchScore(team);
        dto.setMatchScore(score);
        dto.setValidTeam(score > 0);
        // 设置队伍信息
        setTeamInfo(dto, team);
        setTeamAdvantages(dto, team);
        return dto;
    }

    private int calculateMatchScore(List<Agent> team) {
        int score = 0;
        Map<String, Integer> factionCount = new HashMap<>();
        Map<String, Integer> elementCount = new HashMap<>();
        for (Agent agent : team) {
            factionCount.merge(agent.getFaction(), 1, Integer::sum);
            elementCount.merge(agent.getElementType(), 1, Integer::sum);
        }
        for (int count : factionCount.values()) {
            if (count >= 2) {
                score += 3;
            } else if (count == 1) {
                score += 1;
            }
        }
        for (int count : elementCount.values()) {
            if (count >= 2) {
                score += 3;
            } else if (count == 1) {
                score += 1;
            }
        }
        return score;
    }

    private void setTeamInfo(TeamRecommendationDto dto, List<Agent> team) {
        Map<String, Integer> factionCount = new HashMap<>();
        Map<String, Integer> elementCount = new HashMap<>();
        for (Agent agent : team) {
            factionCount.merge(agent.getFaction(), 1, Integer::sum);
            elementCount.merge(agent.getElementType(), 1, Integer::sum);
        }
        boolean hasFactionMatch = factionCount.values().stream().anyMatch(count -> count >= 2);
        boolean hasElementMatch = elementCount.values().stream().anyMatch(count -> count >= 2);
        if (hasFactionMatch && hasElementMatch) {
            dto.setTeamType("同阵营同属性队");
        } else if (hasFactionMatch) {
            dto.setTeamType("同阵营队");
        } else if (hasElementMatch) {
            dto.setTeamType("同属性队");
        } else {
            dto.setTeamType("混搭队");
        }
        StringBuilder composition = new StringBuilder();
        composition.append("主C: ").append(team.get(0).getAgentName())
                .append("(").append(team.get(0).getProfession()).append(")\n");
        for (int i = 1; i < team.size(); i++) {
            composition.append("队友: ").append(team.get(i).getAgentName())
                    .append("(").append(team.get(i).getProfession()).append(")\n");
        }
        dto.setTeamComposition(composition.toString());
    }

    private void setTeamAdvantages(TeamRecommendationDto dto, List<Agent> team) {
        StringBuilder advantages = new StringBuilder();
        Map<String, Integer> factionCount = new HashMap<>();
        Map<String, Integer> elementCount = new HashMap<>();
        for (Agent agent : team) {
            factionCount.merge(agent.getFaction(), 1, Integer::sum);
            elementCount.merge(agent.getElementType(), 1, Integer::sum);
        }
        factionCount.forEach((faction, count) -> {
            if (count >= 2) {
                advantages.append("同阵营加成\n");
            }
        });
        elementCount.forEach((element, count) -> {
            if (count >= 2) {
                advantages.append("同属性加成\n");
            }
        });
        dto.setTeamAdvantage(advantages.toString());
    }

    private AgentDto convertToDto(Agent agent) {
        AgentDto dto = new AgentDto();
        dto.setAgentId(agent.getAgentId());
        dto.setAgentName(agent.getAgentName());
        dto.setGender(agent.getGender());
        dto.setRarity(agent.getRarity());
        dto.setElementType(agent.getElementType());
        dto.setProfession(agent.getProfession());
        dto.setFaction(agent.getFaction());
        dto.setDescription(agent.getDescription());
        dto.setImageUrl(agent.getImageUrl());
        return dto;
    }
} 